Reads
My analyses are based on this course on the Hemberg Lab scRNAseq course
notes:
HE = hemogenic endothelium
Ncx1-/- lack heartbeat
signalling pathways downstream of circulation include Notch
To assess Notch signaling in Ncx1-/- HE and pro-HSCs, we performed bulk and single cell qRT-PCR,
along with markers for endothelial and hematopoietic cells, and identified an aberrant gene expression
signature in pro-HSCs and HE, with upregulation of endothelial genes and downregulation of hematopoietic genes.
This is in line with the hypothesis of a block in hematopoietic development.
Additionally, Jag-1, but not Dll4-mediated Notch signalling appeared to be decreased in Ncx1-/- HE and pro-HSC.
Not only HE and pro-HSCs were affected in the absence of circulation: also aortic smooth muscle cells were reduced,
indicating a change in the cellular composition and potentially signaling environment of the AGM.
library(dplyr)
library(scater)
library(stringr)
library(singleCellTK)
library(biomaRt)
library(stringr)
library(tibble)
library(ggrepel)
reads <- read.table('myriad/temp2', header = TRUE, stringsAsFactors = F)
anno <- read.table('EA2_index-sample_key.csv', header = TRUE, stringsAsFactors = FALSE, sep = ",")
reads <- SingleCellExperiment(assays = list(counts = as.matrix(reads)),
colData = anno)
keep_feature <- rowSums(counts(reads) > 0) > 0
reads <- reads[keep_feature, ]
knitr::kable(summarizeTable(reads))
mouse_mart=useMart(biomart="ensembl", dataset="mmusculus_gene_ensembl")
attr.string = c('ensembl_gene_id', 'external_gene_name', 'chromosome_name')
attr.string = c(attr.string, 'start_position', 'end_position', 'strand')
attr.string = c(attr.string, 'description', 'percentage_gene_gc_content')
attr.string = c(attr.string, 'gene_biotype')
gene.annotation = getBM(attributes=attr.string,
filters = 'ensembl_gene_id',
values = rownames(reads),
mart = mouse_mart)
## some genes do not have annotation because their ids are retired
gene.missing <- setdiff(rownames(reads), gene.annotation$ensembl_gene_id)
genes2keep <- match(gene.annotation$ensembl_gene_id, rownames(reads))
reads <- reads[genes2keep,]
rowData(reads) <- gene.annotation
rownames(reads) <- uniquifyFeatureNames(rowData(reads)$ensembl_gene_id, rowData(reads)$external_gene_name)
is.mito = which(rowData(reads)$chromosome_name == "MT")
reads <- calculateQCMetrics(
reads,
feature_controls = list(
MT = is.mito)
)
##Counts
library(dplyr)
library(scater)
library(stringr)
library(singleCellTK)
library(biomaRt)
library(stringr)
library(tibble)
library(ggrepel)
reads <- readRDS('reads_ea2.rds')
hist(
reads$total_counts,
breaks = 100
)
abline(v = 5.2e5, col = "red")

filter_by_total_counts <- (reads$total_counts > 5.2e5 )
##number of features
hist(
reads$total_features_by_counts_endogenous,
breaks = 100
)
abline(v = 4600, col = "red")

filter_by_expr_features <- (reads$total_features_by_counts_endogenous > 4600)
percent Mitochondrial
hist(reads$pct_counts_MT, breaks = 80)

filter_by_MT <- reads$pct_counts_MT < 10
summary
reads$use <- (
# sufficient features (genes)
filter_by_expr_features &
# mitochondrial reads
filter_by_MT &
# by number of counts
filter_by_total_counts
)
# remove failed
reads <- reads[,reads$use]
knitr::kable(summarizeTable(reads))
| Number of Samples |
371 |
| Number of Genes |
32173 |
| Average number of reads per cell |
719331 |
| Average number of genes per cell |
8076 |
| Samples with <1700 detected genes |
0 |
| Genes with no expression across all samples |
651 |
PCA pre normalization
anno <- read.table('EA2_index-sample_key.csv', header = TRUE, stringsAsFactors = FALSE, sep = ",")
assay(reads, "logcounts") <- log2(counts(reads) + 1)
my_pca <- prcomp(t(logcounts(reads)))
x="PC1"
y="PC2"
x.lab = paste(x, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == x)]^2/sum(my_pca$sdev^2)))
y.lab = paste(y, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == y)]^2/sum(my_pca$sdev^2)))
my_data <- my_pca$x[,1:2]
my_data <- data.frame(my_data) %>% rownames_to_column("pca_rows") %>% dplyr::mutate("pca_rows" = unlist(purrr::map(pca_rows, str_replace, "_N7.+","" )))
my_data <- left_join(my_data,anno, by = c("pca_rows" = "X384_EA2_Nextera.XT_address"))
my_data$geno <- unlist(purrr::map(str_split(my_data$population.name, " "), 1))
my_data$pheno <- unlist(purrr::map(str_split(my_data$population.name, " "), 3))
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(my_data,aes(x = PC1, y = PC2, shape = pheno, colour = geno)) + geom_point(size = 3) + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
labs(x = x.lab, y = y.lab) +
scale_colour_manual(values = cbbPalette ) + ggtitle(label = "PCA pre-normalisation")

Screes
pca.var <- my_pca$sdev^2
pca.var.per <- round(pca.var/sum(pca.var)*100, 1)
barplot(pca.var.per, main="Scree Plot", xlab="Principal Component", ylab="Percent Variation")

pca.var <- my_pca$sdev^2
pca.var.per <- round(pca.var/sum(pca.var)*100, 1)
barplot(pca.var.per[1:20], main="Scree Plot", xlab="Principal Component", ylab="Percent Variation")

TSNE pre normalisation
my_tsnePlot <- scater::plotTSNE(reads, colour_by = "population.name")
my_tsnePlot$data$genotype<-unlist(purrr::map(str_split(my_tsnePlot$data$colour_by, " "), 1))
my_tsnePlot$data$pheno<-unlist(purrr::map(str_split(my_tsnePlot$data$colour_by, " "), 3))
my_data <- my_tsnePlot$data
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(my_data,aes(x = X, y = Y, shape = pheno, colour = genotype)) + geom_point(size = 3) + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
scale_colour_manual(values = cbbPalette ) +
ggtitle(label = "TSNE pre-normalisation")

#saveRDS(reads.use, "reads.rds")
PCA post normalisation
library(scran)
reads <- computeSumFactors(reads)
reads <- scater::normalize(reads)
saveRDS(reads, 'reads_qc.rds')
my_pca<-prcomp(t(logcounts(reads)))
x="PC1"
y="PC2"
x.lab = paste(x, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == x)]^2/sum(my_pca$sdev^2)))
y.lab = paste(y, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == y)]^2/sum(my_pca$sdev^2)))
my_data <- my_pca$x[,1:2]
my_data <- data.frame(my_data) %>% rownames_to_column("pca_rows") %>% dplyr::mutate("pca_rows" = unlist(purrr::map(pca_rows, str_replace, "_N7.+","" )))
my_data <- left_join(my_data,anno, by = c("pca_rows" = "X384_EA2_Nextera.XT_address"))
my_data$geno <- unlist(purrr::map(str_split(my_data$population.name, " "), 1))
my_data$pheno <- unlist(purrr::map(str_split(my_data$population.name, " "), 3))
my_pca_data <- my_data
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(my_data,aes(x = PC1, y = PC2, shape = pheno, colour = geno)) + geom_point(size = 3) + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
labs(x = x.lab, y = y.lab) +
scale_colour_manual(values = cbbPalette ) + ggtitle(label = "PCA post-normalisation")

###Screes
pca.var <- my_pca$sdev^2
pca.var.per <- round(pca.var/sum(pca.var)*100, 1)
barplot(pca.var.per, main="Scree Plot", xlab="Principal Component", ylab="Percent Variation")

pca.var <- my_pca$sdev^2
pca.var.per <- round(pca.var/sum(pca.var)*100, 1)
barplot(pca.var.per[1:20], main="Scree Plot", xlab="Principal Component", ylab="Percent Variation")

TSNE Post normalisation
# my_tsnePlot <- scater::plotTSNE(reads, colour_by = "population.name")
# saveRDS(my_tsnePlot,"my_tsnePlot.rds")
my_tsnePlot <- readRDS("my_tsnePlot.rds")
my_tsnePlot$data$genotype<-unlist(purrr::map(str_split(my_tsnePlot$data$colour_by, " "), 1))
my_tsnePlot$data$pheno<-unlist(purrr::map(str_split(my_tsnePlot$data$colour_by, " "), 3))
my_data <- my_tsnePlot$data
my_data <- my_data %>% rownames_to_column(var = "sample_id") %>% tbl_df()
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(my_data,aes(x = X, y = Y, shape = pheno, colour = genotype)) + geom_point(size = 3) + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
scale_colour_manual(values = cbbPalette ) +
ggtitle(label = "TSNE post-normalisation")

PCA Loadings post normalization
x="PC1"
y="PC2"
x.lab = paste(x, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == x)]^2/sum(my_pca$sdev^2)))
y.lab = paste(y, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == y)]^2/sum(my_pca$sdev^2)))
my_data <- my_pca_data
# extract Loadings
# Extract loadings of the variables
loading_scores_pc1 <- my_pca$rotation[,1]
gene_scores <- abs(loading_scores_pc1)
gene_score_ranked <- sort(gene_scores, decreasing=TRUE)
top_10_genes_PC1 <- names(gene_score_ranked[1:10])
loading_scores_pc2 <- my_pca$rotation[,2]
gene_scores <- abs(loading_scores_pc2)
gene_score_ranked <- sort(gene_scores, decreasing=TRUE)
top_10_genes_PC2 <- names(gene_score_ranked[1:10])
top_20_genes <- c(top_10_genes_PC1,top_10_genes_PC2)
pca_loadings<-data.frame(my_pca$rotation[which(rownames(my_pca$rotation) %in% top_20_genes),])[,1:2]
P <- ggplot(my_data,aes(x = PC1, y = PC2, shape = pheno, colour = geno)) + geom_point(size = 3, alpha =0.6 ) +
theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
labs(x = x.lab, y = y.lab) +
scale_colour_manual(values = cbbPalette ) + ggtitle(label = "PCA post-normalisation")
P + geom_segment(inherit.aes=FALSE,data = pca_loadings, aes(x = 0, y = 0, xend = (PC1),
yend = (PC2)), arrow = arrow(length = unit(1/2, "picas")),
color = "purple") + geom_label_repel(inherit.aes = FALSE, data=pca_loadings, aes(x =(PC1), y= (PC2), label = rownames(pca_loadings)))

##DESeq2 PCA with VST
library(DESeq2)
anno <- colData(reads)[,1:3]
anno$genotype <- unlist(purrr::map(str_split(anno$population.name, " "), 1))
anno$phenotype <- unlist(purrr::map(str_split(anno$population.name, " "), 3))
dds <- DESeqDataSetFromMatrix(countData =counts(reads),colData = anno, design = ~genotype )
rld <- vst(dds)
my_pca <- prcomp(t(assay(rld)))
x="PC1"
y="PC2"
x.lab = paste(x, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == x)]^2/sum(my_pca$sdev^2)))
y.lab = paste(y, sprintf('(%0.1f%% explained var.)', 100 * my_pca$sdev[which(colnames(my_pca$x) == y)]^2/sum(my_pca$sdev^2)))
my_data <- my_pca$x[,1:2]
my_data<-left_join(rownames_to_column(data.frame(my_data),"pca_rows"),rownames_to_column(data.frame(anno),"sample_id"), by = c("pca_rows" = "sample_id"))
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(my_data,aes(x = PC1, y = PC2, shape = phenotype, colour = genotype)) + geom_point(size = 3) + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray94",
size = 0.35), panel.grid.minor = element_line(colour = "gray98",
size = 0.1), panel.background = element_rect(fill = NA),
legend.key = element_rect(fill = NA),
legend.background = element_rect(fill = NA)) +
labs(colour = "genotype") + labs(shape = "phenotype") +
labs(x = x.lab, y = y.lab) +
scale_colour_manual(values = cbbPalette ) + ggtitle(label = "PCA DESeq2 VST-normalisation")

Mean count per gene
counts <- counts(reads)
nGenes <- length(counts[,1])
coverage <- colSums(counts)/nGenes
reads$genotype<-unlist(purrr::map(str_split(reads$population.name, " "), 1))
cell.labels <- reads$genotype
colnames(counts) <- cell.labels
cell.labels <- as.factor(cell.labels)
cov_df<-data.frame(coverage)
cov_df$names<-cell.labels
ggplot(cov_df, aes(x=names,y=coverage)) + geom_violin() + geom_jitter() + theme(axis.line = element_line(size = 0.5,
linetype = "solid"), panel.grid.major = element_line(colour = "gray90"),
panel.grid.minor = element_line(colour = "gray94",
linetype = "dashed"), panel.background = element_rect(fill = NA))

playing with histograms
library(tidyverse)
my_goi<-c("Dll4","Efnb2","Erg","Gata2","Gfi1","Hes1","Hey1","Hey2","Itga2b","Jag1","Jag2","Kdr","Klf2","Lmo2","Myb","Notch1","Notch4","Runx1","Tal1","Tek","Gapdh","Ubc")
mcols(reads)$strand<-NULL
my_reads<-reads[which(rownames(reads) %in% my_goi),]
my_df<-data.frame(logcounts(my_reads))
colnames(my_df) <- str_replace(my_reads$population.name," #[0-9]+ " ,"_")
my_df<-my_df %>% rownames_to_column('gene')
my_df<- gather(my_df,condition,count,-gene)
my_df$condition<-str_replace(my_df$condition,"\\.[0-9]+","")
base <- ggplot(my_df,aes(count, fill=condition)) + geom_histogram(aes(y = ..count..),bins = 50) + scale_y_continuous(trans="log1p", breaks = NULL)
base + facet_wrap(~gene) + theme_bw() + xlab(label = "normalised log count") + ylab(label="cell count")

variation explained
reads$condition_ID_main <- str_replace(my_reads$population.name," #[0-9]+ " ,"_")
reads$genotype <- unlist(purrr::map(str_split(reads$population.name, " "), 1))
reads$phenotype <- unlist(purrr::map(str_split(reads$population.name, " "), 3))
my_vars<-getVarianceExplained(reads, exprs_values = "logcounts", variables = c("population.name", "condition_ID_main","genotype","phenotype"))
plotExplanatoryVariables(my_vars)

LS0tCnRpdGxlOiAiRUEyIE5leHRTZXEgUHJlbGltIgphdXRob3I6IDxhIGhyZWY9Imh0dHBzOi8vY2hlbGEtamFtZXMuZ2l0aHViLmlvLyI+IDxoMz4gQ2hlbGEgSmFtZXMgPC9oMz4gPC9hPiBcbmV3bGluZSBDYW5jZXIgSW5zdGl0dXRlLCBVQ0wsIFVLCmRhdGU6IDIzIEFwcmlsIDIwMTkKb3V0cHV0OgogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICBrZWVwX21kOiBmYWxzZQogICAgZW5jb2Rpbmc6ICJVVEYtOCIKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9Cmh0bWx0b29sczo6dGFnTGlzdChybWFya2Rvd246Omh0bWxfZGVwZW5kZW5jeV9mb250X2F3ZXNvbWUoKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGV2YWwgPSBUUlVFLCBjYWNoZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgojIyBSZWFkcwoKW015IGFuYWx5c2VzIGFyZSBiYXNlZCBvbiB0aGlzIGNvdXJzZSBvbiB0aGUgSGVtYmVyZyBMYWIgc2NSTkFzZXEgY291cnNlCl0oaHR0cHM6Ly9oZW1iZXJnLWxhYi5naXRodWIuaW8vc2NSTkEuc2VxLmNvdXJzZS9jbGVhbmluZy10aGUtZXhwcmVzc2lvbi1tYXRyaXguaHRtbCNleHByZXNzaW9uLXFjLXJlYWRzKQoKbm90ZXM6CkhFICA9IGhlbW9nZW5pYyBlbmRvdGhlbGl1bSAKTmN4MS0vLSBsYWNrIGhlYXJ0YmVhdApzaWduYWxsaW5nIHBhdGh3YXlzIGRvd25zdHJlYW0gb2YgY2lyY3VsYXRpb24gaW5jbHVkZSBOb3RjaAoKVG8gYXNzZXNzIE5vdGNoIHNpZ25hbGluZyBpbiBOY3gxLS8tICBIRSBhbmQgcHJvLUhTQ3MsIHdlIHBlcmZvcm1lZCBidWxrIGFuZCBzaW5nbGUgY2VsbCBxUlQtUENSLCAKYWxvbmcgd2l0aCBtYXJrZXJzIGZvciBlbmRvdGhlbGlhbCBhbmQgaGVtYXRvcG9pZXRpYyBjZWxscywgYW5kIGlkZW50aWZpZWQgYW4gYWJlcnJhbnQgZ2VuZSBleHByZXNzaW9uIApzaWduYXR1cmUgaW4gcHJvLUhTQ3MgYW5kIEhFLCB3aXRoIHVwcmVndWxhdGlvbiBvZiBlbmRvdGhlbGlhbCBnZW5lcyBhbmQgZG93bnJlZ3VsYXRpb24gb2YgaGVtYXRvcG9pZXRpYyBnZW5lcy4gClRoaXMgaXMgaW4gbGluZSB3aXRoIHRoZSBoeXBvdGhlc2lzIG9mIGEgYmxvY2sgaW4gaGVtYXRvcG9pZXRpYyBkZXZlbG9wbWVudC4gCkFkZGl0aW9uYWxseSwgSmFnLTEsIGJ1dCBub3QgRGxsNC1tZWRpYXRlZCBOb3RjaCBzaWduYWxsaW5nIGFwcGVhcmVkIHRvIGJlIGRlY3JlYXNlZCBpbiBOY3gxLS8tIEhFIGFuZCBwcm8tSFNDLiAKTm90IG9ubHkgSEUgYW5kIHByby1IU0NzIHdlcmUgYWZmZWN0ZWQgaW4gdGhlIGFic2VuY2Ugb2YgY2lyY3VsYXRpb246IGFsc28gYW9ydGljIHNtb290aCBtdXNjbGUgY2VsbHMgd2VyZSByZWR1Y2VkLCAKaW5kaWNhdGluZyBhIGNoYW5nZSBpbiB0aGUgY2VsbHVsYXIgY29tcG9zaXRpb24gYW5kIHBvdGVudGlhbGx5IHNpZ25hbGluZyBlbnZpcm9ubWVudCBvZiB0aGUgQUdNLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIGV2YWwgPSBGfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNjYXRlcikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHNpbmdsZUNlbGxUSykKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGdncmVwZWwpCnJlYWRzIDwtIHJlYWQudGFibGUoJ215cmlhZC90ZW1wMicsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQphbm5vIDwtIHJlYWQudGFibGUoJ0VBMl9pbmRleC1zYW1wbGVfa2V5LmNzdicsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgc2VwID0gIiwiKQoKcmVhZHMgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQoYXNzYXlzID0gbGlzdChjb3VudHMgPSBhcy5tYXRyaXgocmVhZHMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGFubm8pCgprZWVwX2ZlYXR1cmUgPC0gcm93U3Vtcyhjb3VudHMocmVhZHMpID4gMCkgPiAwCnJlYWRzIDwtIHJlYWRzW2tlZXBfZmVhdHVyZSwgXQprbml0cjo6a2FibGUoc3VtbWFyaXplVGFibGUocmVhZHMpKQoKbW91c2VfbWFydD11c2VNYXJ0KGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIikKCmF0dHIuc3RyaW5nID0gYygnZW5zZW1ibF9nZW5lX2lkJywgJ2V4dGVybmFsX2dlbmVfbmFtZScsICdjaHJvbW9zb21lX25hbWUnKQphdHRyLnN0cmluZyA9IGMoYXR0ci5zdHJpbmcsICdzdGFydF9wb3NpdGlvbicsICdlbmRfcG9zaXRpb24nLCAnc3RyYW5kJykKYXR0ci5zdHJpbmcgPSBjKGF0dHIuc3RyaW5nLCAnZGVzY3JpcHRpb24nLCAncGVyY2VudGFnZV9nZW5lX2djX2NvbnRlbnQnKQphdHRyLnN0cmluZyA9IGMoYXR0ci5zdHJpbmcsICdnZW5lX2Jpb3R5cGUnKQoKCmdlbmUuYW5ub3RhdGlvbiA9IGdldEJNKGF0dHJpYnV0ZXM9YXR0ci5zdHJpbmcsIAogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXJzID0gICdlbnNlbWJsX2dlbmVfaWQnLCAKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gcm93bmFtZXMocmVhZHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbWFydCA9IG1vdXNlX21hcnQpCgojIyBzb21lIGdlbmVzIGRvIG5vdCBoYXZlIGFubm90YXRpb24gYmVjYXVzZSB0aGVpciBpZHMgYXJlIHJldGlyZWQKCmdlbmUubWlzc2luZyA8LSBzZXRkaWZmKHJvd25hbWVzKHJlYWRzKSwgZ2VuZS5hbm5vdGF0aW9uJGVuc2VtYmxfZ2VuZV9pZCkKCgpnZW5lczJrZWVwIDwtIG1hdGNoKGdlbmUuYW5ub3RhdGlvbiRlbnNlbWJsX2dlbmVfaWQsIHJvd25hbWVzKHJlYWRzKSkKcmVhZHMgPC0gcmVhZHNbZ2VuZXMya2VlcCxdCnJvd0RhdGEocmVhZHMpIDwtIGdlbmUuYW5ub3RhdGlvbgpyb3duYW1lcyhyZWFkcykgPC0gdW5pcXVpZnlGZWF0dXJlTmFtZXMocm93RGF0YShyZWFkcykkZW5zZW1ibF9nZW5lX2lkLCByb3dEYXRhKHJlYWRzKSRleHRlcm5hbF9nZW5lX25hbWUpCgppcy5taXRvID0gd2hpY2gocm93RGF0YShyZWFkcykkY2hyb21vc29tZV9uYW1lID09ICJNVCIpCnJlYWRzIDwtIGNhbGN1bGF0ZVFDTWV0cmljcygKICAgIHJlYWRzLAogICAgZmVhdHVyZV9jb250cm9scyA9IGxpc3QoCiAgICAgICAgTVQgPSAgaXMubWl0bykKICAgICkKCmBgYAoKIyNDb3VudHMKCmBgYHtyLCBtZXNzYWdlPUYsd2FybmluZz1GfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNjYXRlcikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHNpbmdsZUNlbGxUSykKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGdncmVwZWwpCnJlYWRzIDwtIHJlYWRSRFMoJ3JlYWRzX2VhMi5yZHMnKQpoaXN0KAogICAgcmVhZHMkdG90YWxfY291bnRzLAogICAgYnJlYWtzID0gMTAwCikKYWJsaW5lKHYgPSA1LjJlNSwgY29sID0gInJlZCIpCgpmaWx0ZXJfYnlfdG90YWxfY291bnRzIDwtIChyZWFkcyR0b3RhbF9jb3VudHMgPiA1LjJlNSApCmBgYAoKIyNudW1iZXIgb2YgZmVhdHVyZXMKCmBgYHtyfQpoaXN0KAogICAgcmVhZHMkdG90YWxfZmVhdHVyZXNfYnlfY291bnRzX2VuZG9nZW5vdXMsCiAgICBicmVha3MgPSAxMDAKKQphYmxpbmUodiA9IDQ2MDAsIGNvbCA9ICJyZWQiKQoKZmlsdGVyX2J5X2V4cHJfZmVhdHVyZXMgPC0gKHJlYWRzJHRvdGFsX2ZlYXR1cmVzX2J5X2NvdW50c19lbmRvZ2Vub3VzID4gNDYwMCkKCmBgYAoKIyMgcGVyY2VudCBNaXRvY2hvbmRyaWFsCgpgYGB7cn0KaGlzdChyZWFkcyRwY3RfY291bnRzX01ULCBicmVha3MgPSA4MCkKZmlsdGVyX2J5X01UIDwtIHJlYWRzJHBjdF9jb3VudHNfTVQgPCAxMApgYGAKCiMjIHN1bW1hcnkKCmBgYHtyfQpyZWFkcyR1c2UgPC0gKAogICAgIyBzdWZmaWNpZW50IGZlYXR1cmVzIChnZW5lcykKICAgIGZpbHRlcl9ieV9leHByX2ZlYXR1cmVzICYKICAgICMgbWl0b2Nob25kcmlhbCByZWFkcwogICAgZmlsdGVyX2J5X01UICYKICAgICMgYnkgbnVtYmVyIG9mIGNvdW50cwogICAgZmlsdGVyX2J5X3RvdGFsX2NvdW50cwopCgojIHJlbW92ZSBmYWlsZWQgCnJlYWRzIDwtIHJlYWRzWyxyZWFkcyR1c2VdCgprbml0cjo6a2FibGUoc3VtbWFyaXplVGFibGUocmVhZHMpKQoKYGBgCgojIyBQQ0EgcHJlIG5vcm1hbGl6YXRpb24KCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KCmFubm8gPC0gcmVhZC50YWJsZSgnRUEyX2luZGV4LXNhbXBsZV9rZXkuY3N2JywgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBzZXAgPSAiLCIpCmFzc2F5KHJlYWRzLCAibG9nY291bnRzIikgPC0gbG9nMihjb3VudHMocmVhZHMpICsgMSkKCm15X3BjYSA8LSBwcmNvbXAodChsb2djb3VudHMocmVhZHMpKSkKCng9IlBDMSIKeT0iUEMyIgp4LmxhYiA9IHBhc3RlKHgsIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB4KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQp5LmxhYiA9IHBhc3RlKHksIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB5KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQpteV9kYXRhIDwtIG15X3BjYSR4WywxOjJdCm15X2RhdGEgPC0gZGF0YS5mcmFtZShteV9kYXRhKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJwY2Ffcm93cyIpICU+JSBkcGx5cjo6bXV0YXRlKCJwY2Ffcm93cyIgPSB1bmxpc3QocHVycnI6Om1hcChwY2Ffcm93cywgc3RyX3JlcGxhY2UsICJfTjcuKyIsIiIgKSkpCgpteV9kYXRhIDwtIGxlZnRfam9pbihteV9kYXRhLGFubm8sIGJ5ID0gYygicGNhX3Jvd3MiID0gIlgzODRfRUEyX05leHRlcmEuWFRfYWRkcmVzcyIpKQoKbXlfZGF0YSRnZW5vIDwtIHVubGlzdChwdXJycjo6bWFwKHN0cl9zcGxpdChteV9kYXRhJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMSkpCm15X2RhdGEkcGhlbm8gPC0gdW5saXN0KHB1cnJyOjptYXAoc3RyX3NwbGl0KG15X2RhdGEkcG9wdWxhdGlvbi5uYW1lLCAiICIpLCAzKSkKCmNiYlBhbGV0dGUgPC0gYygiIzAwMDAwMCIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwOUU3MyIsICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKZ2dwbG90KG15X2RhdGEsYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gcGhlbm8sIGNvbG91ciA9IGdlbm8pKSArIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjUsIAogICAgbGluZXR5cGUgPSAic29saWQiKSwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTk0IiwgCiAgICBzaXplID0gMC4zNSksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5OCIsIAogICAgc2l6ZSA9IDAuMSksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwgCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSkgKyAKICAgIGxhYnMoY29sb3VyID0gImdlbm90eXBlIikgKyBsYWJzKHNoYXBlID0gInBoZW5vdHlwZSIpICsKICAgIGxhYnMoeCA9IHgubGFiLCB5ID0geS5sYWIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY2JiUGFsZXR0ZSApICsgZ2d0aXRsZShsYWJlbCA9ICJQQ0EgcHJlLW5vcm1hbGlzYXRpb24iKQpgYGAKCiMjIyBTY3JlZXMKCmBgYHtyfQpwY2EudmFyIDwtIG15X3BjYSRzZGV2XjIKcGNhLnZhci5wZXIgPC0gcm91bmQocGNhLnZhci9zdW0ocGNhLnZhcikqMTAwLCAxKQogCmJhcnBsb3QocGNhLnZhci5wZXIsIG1haW49IlNjcmVlIFBsb3QiLCB4bGFiPSJQcmluY2lwYWwgQ29tcG9uZW50IiwgeWxhYj0iUGVyY2VudCBWYXJpYXRpb24iKQpgYGAKCgpgYGB7cn0KcGNhLnZhciA8LSBteV9wY2Ekc2Rldl4yCnBjYS52YXIucGVyIDwtIHJvdW5kKHBjYS52YXIvc3VtKHBjYS52YXIpKjEwMCwgMSkKIApiYXJwbG90KHBjYS52YXIucGVyWzE6MjBdLCBtYWluPSJTY3JlZSBQbG90IiwgeGxhYj0iUHJpbmNpcGFsIENvbXBvbmVudCIsIHlsYWI9IlBlcmNlbnQgVmFyaWF0aW9uIikKYGBgCgojIyBUU05FIHByZSBub3JtYWxpc2F0aW9uCgpgYGB7cn0KbXlfdHNuZVBsb3QgPC0gc2NhdGVyOjpwbG90VFNORShyZWFkcywgY29sb3VyX2J5ID0gInBvcHVsYXRpb24ubmFtZSIpCgpteV90c25lUGxvdCRkYXRhJGdlbm90eXBlPC11bmxpc3QocHVycnI6Om1hcChzdHJfc3BsaXQobXlfdHNuZVBsb3QkZGF0YSRjb2xvdXJfYnksICIgIiksIDEpKQpteV90c25lUGxvdCRkYXRhJHBoZW5vPC11bmxpc3QocHVycnI6Om1hcChzdHJfc3BsaXQobXlfdHNuZVBsb3QkZGF0YSRjb2xvdXJfYnksICIgIiksIDMpKQoKbXlfZGF0YSA8LSBteV90c25lUGxvdCRkYXRhCgpjYmJQYWxldHRlIDwtIGMoIiMwMDAwMDAiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiMwMDlFNzMiLCAiI0YwRTQ0MiIsICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiI0NDNzlBNyIpCmdncGxvdChteV9kYXRhLGFlcyh4ID0gWCwgeSA9IFksIHNoYXBlID0gcGhlbm8sIGNvbG91ciA9IGdlbm90eXBlKSkgKyBnZW9tX3BvaW50KHNpemUgPSAzKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC41LCAKICAgIGxpbmV0eXBlID0gInNvbGlkIiksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5NCIsIAogICAgc2l6ZSA9IDAuMzUpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5OTgiLCAKICAgIHNpemUgPSAwLjEpLCBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLCAKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsgCiAgICBsYWJzKGNvbG91ciA9ICJnZW5vdHlwZSIpICsgbGFicyhzaGFwZSA9ICJwaGVub3R5cGUiKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNiYlBhbGV0dGUgKSArCiAgICBnZ3RpdGxlKGxhYmVsID0gIlRTTkUgcHJlLW5vcm1hbGlzYXRpb24iKQoKI3NhdmVSRFMocmVhZHMudXNlLCAicmVhZHMucmRzIikKYGBgCgojIyBQQ0EgcG9zdCBub3JtYWxpc2F0aW9uCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9Rn0KbGlicmFyeShzY3JhbikKCnJlYWRzIDwtIGNvbXB1dGVTdW1GYWN0b3JzKHJlYWRzKQpyZWFkcyA8LSBzY2F0ZXI6Om5vcm1hbGl6ZShyZWFkcykKc2F2ZVJEUyhyZWFkcywgJ3JlYWRzX3FjLnJkcycpCm15X3BjYTwtcHJjb21wKHQobG9nY291bnRzKHJlYWRzKSkpCgp4PSJQQzEiCnk9IlBDMiIKeC5sYWIgPSBwYXN0ZSh4LCBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCAxMDAgKiBteV9wY2Ekc2Rldlt3aGljaChjb2xuYW1lcyhteV9wY2EkeCkgPT0geCldXjIvc3VtKG15X3BjYSRzZGV2XjIpKSkKeS5sYWIgPSBwYXN0ZSh5LCBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCAxMDAgKiBteV9wY2Ekc2Rldlt3aGljaChjb2xuYW1lcyhteV9wY2EkeCkgPT0geSldXjIvc3VtKG15X3BjYSRzZGV2XjIpKSkKbXlfZGF0YSA8LSBteV9wY2EkeFssMToyXQpteV9kYXRhIDwtIGRhdGEuZnJhbWUobXlfZGF0YSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigicGNhX3Jvd3MiKSAlPiUgZHBseXI6Om11dGF0ZSgicGNhX3Jvd3MiID0gdW5saXN0KHB1cnJyOjptYXAocGNhX3Jvd3MsIHN0cl9yZXBsYWNlLCAiX043LisiLCIiICkpKQoKbXlfZGF0YSA8LSBsZWZ0X2pvaW4obXlfZGF0YSxhbm5vLCBieSA9IGMoInBjYV9yb3dzIiA9ICJYMzg0X0VBMl9OZXh0ZXJhLlhUX2FkZHJlc3MiKSkKCm15X2RhdGEkZ2VubyA8LSB1bmxpc3QocHVycnI6Om1hcChzdHJfc3BsaXQobXlfZGF0YSRwb3B1bGF0aW9uLm5hbWUsICIgIiksIDEpKQpteV9kYXRhJHBoZW5vIDwtIHVubGlzdChwdXJycjo6bWFwKHN0cl9zcGxpdChteV9kYXRhJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMykpCgpteV9wY2FfZGF0YSA8LSBteV9kYXRhCmNiYlBhbGV0dGUgPC0gYygiIzAwMDAwMCIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwOUU3MyIsICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKZ2dwbG90KG15X2RhdGEsYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gcGhlbm8sIGNvbG91ciA9IGdlbm8pKSArIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjUsIAogICAgbGluZXR5cGUgPSAic29saWQiKSwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTk0IiwgCiAgICBzaXplID0gMC4zNSksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5OCIsIAogICAgc2l6ZSA9IDAuMSksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwgCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSkgKyAKICAgIGxhYnMoY29sb3VyID0gImdlbm90eXBlIikgKyBsYWJzKHNoYXBlID0gInBoZW5vdHlwZSIpICsKICAgIGxhYnMoeCA9IHgubGFiLCB5ID0geS5sYWIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY2JiUGFsZXR0ZSApICsgZ2d0aXRsZShsYWJlbCA9ICJQQ0EgcG9zdC1ub3JtYWxpc2F0aW9uIikKYGBgCgojIyNTY3JlZXMKCmBgYHtyfQpwY2EudmFyIDwtIG15X3BjYSRzZGV2XjIKcGNhLnZhci5wZXIgPC0gcm91bmQocGNhLnZhci9zdW0ocGNhLnZhcikqMTAwLCAxKQogCmJhcnBsb3QocGNhLnZhci5wZXIsIG1haW49IlNjcmVlIFBsb3QiLCB4bGFiPSJQcmluY2lwYWwgQ29tcG9uZW50IiwgeWxhYj0iUGVyY2VudCBWYXJpYXRpb24iKQoKYGBgCgpgYGB7cn0KcGNhLnZhciA8LSBteV9wY2Ekc2Rldl4yCnBjYS52YXIucGVyIDwtIHJvdW5kKHBjYS52YXIvc3VtKHBjYS52YXIpKjEwMCwgMSkKYmFycGxvdChwY2EudmFyLnBlclsxOjIwXSwgbWFpbj0iU2NyZWUgUGxvdCIsIHhsYWI9IlByaW5jaXBhbCBDb21wb25lbnQiLCB5bGFiPSJQZXJjZW50IFZhcmlhdGlvbiIpCmBgYAoKIyMgVFNORSAgUG9zdCBub3JtYWxpc2F0aW9uCgpgYGB7cn0KCiMgbXlfdHNuZVBsb3QgPC0gc2NhdGVyOjpwbG90VFNORShyZWFkcywgY29sb3VyX2J5ID0gInBvcHVsYXRpb24ubmFtZSIpCiMgc2F2ZVJEUyhteV90c25lUGxvdCwibXlfdHNuZVBsb3QucmRzIikKbXlfdHNuZVBsb3QgPC0gcmVhZFJEUygibXlfdHNuZVBsb3QucmRzIikKbXlfdHNuZVBsb3QkZGF0YSRnZW5vdHlwZTwtdW5saXN0KHB1cnJyOjptYXAoc3RyX3NwbGl0KG15X3RzbmVQbG90JGRhdGEkY29sb3VyX2J5LCAiICIpLCAxKSkKbXlfdHNuZVBsb3QkZGF0YSRwaGVubzwtdW5saXN0KHB1cnJyOjptYXAoc3RyX3NwbGl0KG15X3RzbmVQbG90JGRhdGEkY29sb3VyX2J5LCAiICIpLCAzKSkKCm15X2RhdGEgPC0gbXlfdHNuZVBsb3QkZGF0YQpteV9kYXRhIDwtIG15X2RhdGEgJT4lIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2FtcGxlX2lkIikgJT4lIHRibF9kZigpCgpjYmJQYWxldHRlIDwtIGMoIiMwMDAwMDAiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiMwMDlFNzMiLCAiI0YwRTQ0MiIsICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiI0NDNzlBNyIpCmdncGxvdChteV9kYXRhLGFlcyh4ID0gWCwgeSA9IFksIHNoYXBlID0gcGhlbm8sIGNvbG91ciA9IGdlbm90eXBlKSkgKyBnZW9tX3BvaW50KHNpemUgPSAzKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC41LCAKICAgIGxpbmV0eXBlID0gInNvbGlkIiksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5NCIsIAogICAgc2l6ZSA9IDAuMzUpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5OTgiLCAKICAgIHNpemUgPSAwLjEpLCBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLCAKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsgCiAgICBsYWJzKGNvbG91ciA9ICJnZW5vdHlwZSIpICsgbGFicyhzaGFwZSA9ICJwaGVub3R5cGUiKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNiYlBhbGV0dGUgKSArCiAgICBnZ3RpdGxlKGxhYmVsID0gIlRTTkUgcG9zdC1ub3JtYWxpc2F0aW9uIikKCgoKYGBgCgoKIyMgUENBIExvYWRpbmdzIHBvc3Qgbm9ybWFsaXphdGlvbgoKYGBge3J9Cng9IlBDMSIKeT0iUEMyIgp4LmxhYiA9IHBhc3RlKHgsIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB4KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQp5LmxhYiA9IHBhc3RlKHksIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB5KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQoKbXlfZGF0YSA8LSBteV9wY2FfZGF0YQojIGV4dHJhY3QgTG9hZGluZ3MKIyBFeHRyYWN0IGxvYWRpbmdzIG9mIHRoZSB2YXJpYWJsZXMKbG9hZGluZ19zY29yZXNfcGMxIDwtIG15X3BjYSRyb3RhdGlvblssMV0KZ2VuZV9zY29yZXMgPC0gYWJzKGxvYWRpbmdfc2NvcmVzX3BjMSkKZ2VuZV9zY29yZV9yYW5rZWQgPC0gc29ydChnZW5lX3Njb3JlcywgZGVjcmVhc2luZz1UUlVFKQp0b3BfMTBfZ2VuZXNfUEMxIDwtIG5hbWVzKGdlbmVfc2NvcmVfcmFua2VkWzE6MTBdKQoKbG9hZGluZ19zY29yZXNfcGMyIDwtIG15X3BjYSRyb3RhdGlvblssMl0KZ2VuZV9zY29yZXMgPC0gYWJzKGxvYWRpbmdfc2NvcmVzX3BjMikKZ2VuZV9zY29yZV9yYW5rZWQgPC0gc29ydChnZW5lX3Njb3JlcywgZGVjcmVhc2luZz1UUlVFKQp0b3BfMTBfZ2VuZXNfUEMyIDwtIG5hbWVzKGdlbmVfc2NvcmVfcmFua2VkWzE6MTBdKQoKdG9wXzIwX2dlbmVzIDwtIGModG9wXzEwX2dlbmVzX1BDMSx0b3BfMTBfZ2VuZXNfUEMyKQpwY2FfbG9hZGluZ3M8LWRhdGEuZnJhbWUobXlfcGNhJHJvdGF0aW9uW3doaWNoKHJvd25hbWVzKG15X3BjYSRyb3RhdGlvbikgJWluJSB0b3BfMjBfZ2VuZXMpLF0pWywxOjJdCgpQIDwtIGdncGxvdChteV9kYXRhLGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBzaGFwZSA9IHBoZW5vLCBjb2xvdXIgPSBnZW5vKSkgKyBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9MC42ICkgKwogICAgdGhlbWUoYXhpcy5saW5lID0gICBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNSwgCiAgICBsaW5ldHlwZSA9ICJzb2xpZCIpLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5OTQiLCAKICAgIHNpemUgPSAwLjM1KSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTk4IiwgCiAgICBzaXplID0gMC4xKSwgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLCAKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwgCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpKSArIAogICAgbGFicyhjb2xvdXIgPSAiZ2Vub3R5cGUiKSArIGxhYnMoc2hhcGUgPSAicGhlbm90eXBlIikgKwogICAgbGFicyh4ID0geC5sYWIsIHkgPSB5LmxhYikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjYmJQYWxldHRlICkgKyBnZ3RpdGxlKGxhYmVsID0gIlBDQSBwb3N0LW5vcm1hbGlzYXRpb24iKQoKUCArIGdlb21fc2VnbWVudChpbmhlcml0LmFlcz1GQUxTRSxkYXRhID0gcGNhX2xvYWRpbmdzLCBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gKFBDMSksCiAgICAgeWVuZCA9IChQQzIpKSwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEvMiwgInBpY2FzIikpLAogICAgIGNvbG9yID0gInB1cnBsZSIpICsgZ2VvbV9sYWJlbF9yZXBlbChpbmhlcml0LmFlcyA9IEZBTFNFLCBkYXRhPXBjYV9sb2FkaW5ncywgYWVzKHggPShQQzEpLCB5PSAoUEMyKSwgbGFiZWwgPSByb3duYW1lcyhwY2FfbG9hZGluZ3MpKSkKCgpgYGAKCiMjREVTZXEyIFBDQSB3aXRoIFZTVAoKYGBge3IgLCBtZXNzYWdlID0gRiwgd2FybmluZz1GfQpsaWJyYXJ5KERFU2VxMikKYW5ubyA8LSBjb2xEYXRhKHJlYWRzKVssMTozXQphbm5vJGdlbm90eXBlIDwtIHVubGlzdChwdXJycjo6bWFwKHN0cl9zcGxpdChhbm5vJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMSkpCmFubm8kcGhlbm90eXBlIDwtIHVubGlzdChwdXJycjo6bWFwKHN0cl9zcGxpdChhbm5vJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMykpCmRkcyAgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPWNvdW50cyhyZWFkcyksY29sRGF0YSA9IGFubm8sIGRlc2lnbiA9IH5nZW5vdHlwZSApCnJsZCAgPC0gdnN0KGRkcykKCm15X3BjYSA8LSBwcmNvbXAodChhc3NheShybGQpKSkKCng9IlBDMSIKeT0iUEMyIgp4LmxhYiA9IHBhc3RlKHgsIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB4KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQp5LmxhYiA9IHBhc3RlKHksIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIDEwMCAqIG15X3BjYSRzZGV2W3doaWNoKGNvbG5hbWVzKG15X3BjYSR4KSA9PSB5KV1eMi9zdW0obXlfcGNhJHNkZXZeMikpKQpteV9kYXRhIDwtIG15X3BjYSR4WywxOjJdCgoKbXlfZGF0YTwtbGVmdF9qb2luKHJvd25hbWVzX3RvX2NvbHVtbihkYXRhLmZyYW1lKG15X2RhdGEpLCJwY2Ffcm93cyIpLHJvd25hbWVzX3RvX2NvbHVtbihkYXRhLmZyYW1lKGFubm8pLCJzYW1wbGVfaWQiKSwgYnkgPSBjKCJwY2Ffcm93cyIgPSAic2FtcGxlX2lkIikpCgoKY2JiUGFsZXR0ZSA8LSBjKCIjMDAwMDAwIiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwgIiNGMEU0NDIiLCAiIzAwNzJCMiIsICIjRDU1RTAwIiwgIiNDQzc5QTciKQpnZ3Bsb3QobXlfZGF0YSxhZXMoeCA9IFBDMSwgeSA9IFBDMiwgc2hhcGUgPSBwaGVub3R5cGUsIGNvbG91ciA9IGdlbm90eXBlKSkgKyBnZW9tX3BvaW50KHNpemUgPSAzKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC41LCAKICAgIGxpbmV0eXBlID0gInNvbGlkIiksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5NCIsIAogICAgc2l6ZSA9IDAuMzUpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5OTgiLCAKICAgIHNpemUgPSAwLjEpLCBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLCAKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsgCiAgICBsYWJzKGNvbG91ciA9ICJnZW5vdHlwZSIpICsgbGFicyhzaGFwZSA9ICJwaGVub3R5cGUiKSArCiAgICBsYWJzKHggPSB4LmxhYiwgeSA9IHkubGFiKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNiYlBhbGV0dGUgKSArIGdndGl0bGUobGFiZWwgPSAiUENBIERFU2VxMiBWU1Qtbm9ybWFsaXNhdGlvbiIpCgpgYGAKCiMjIE1lYW4gY291bnQgcGVyIGdlbmUKCmBgYHtyfQpjb3VudHMgPC0gY291bnRzKHJlYWRzKQpuR2VuZXMgPC0gbGVuZ3RoKGNvdW50c1ssMV0pCgpjb3ZlcmFnZSA8LSBjb2xTdW1zKGNvdW50cykvbkdlbmVzCgpyZWFkcyRnZW5vdHlwZTwtdW5saXN0KHB1cnJyOjptYXAoc3RyX3NwbGl0KHJlYWRzJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMSkpCgpjZWxsLmxhYmVscyA8LSByZWFkcyRnZW5vdHlwZQpjb2xuYW1lcyhjb3VudHMpIDwtIGNlbGwubGFiZWxzCmNlbGwubGFiZWxzIDwtIGFzLmZhY3RvcihjZWxsLmxhYmVscykKY292X2RmPC1kYXRhLmZyYW1lKGNvdmVyYWdlKQpjb3ZfZGYkbmFtZXM8LWNlbGwubGFiZWxzCgpnZ3Bsb3QoY292X2RmLCBhZXMoeD1uYW1lcyx5PWNvdmVyYWdlKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2VvbV9qaXR0ZXIoKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC41LCAKICAgIGxpbmV0eXBlID0gInNvbGlkIiksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5MCIpLCAKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5NCIsIAogICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpLCBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpCgpgYGAKCiMjIHBsYXlpbmcgd2l0aCBoaXN0b2dyYW1zCgpgYGB7ciwgd2FybmluZz1GLG1lc3NhZ2U9Rn0KbGlicmFyeSh0aWR5dmVyc2UpCm15X2dvaTwtYygiRGxsNCIsIkVmbmIyIiwiRXJnIiwiR2F0YTIiLCJHZmkxIiwiSGVzMSIsIkhleTEiLCJIZXkyIiwiSXRnYTJiIiwiSmFnMSIsIkphZzIiLCJLZHIiLCJLbGYyIiwiTG1vMiIsIk15YiIsIk5vdGNoMSIsIk5vdGNoNCIsIlJ1bngxIiwiVGFsMSIsIlRlayIsIkdhcGRoIiwiVWJjIikKbWNvbHMocmVhZHMpJHN0cmFuZDwtTlVMTApteV9yZWFkczwtcmVhZHNbd2hpY2gocm93bmFtZXMocmVhZHMpICVpbiUgbXlfZ29pKSxdCm15X2RmPC1kYXRhLmZyYW1lKGxvZ2NvdW50cyhteV9yZWFkcykpCmNvbG5hbWVzKG15X2RmKSA8LSBzdHJfcmVwbGFjZShteV9yZWFkcyRwb3B1bGF0aW9uLm5hbWUsIiAjWzAtOV0rICIgLCJfIikKbXlfZGY8LW15X2RmICU+JSByb3duYW1lc190b19jb2x1bW4oJ2dlbmUnKQpteV9kZjwtIGdhdGhlcihteV9kZixjb25kaXRpb24sY291bnQsLWdlbmUpCm15X2RmJGNvbmRpdGlvbjwtc3RyX3JlcGxhY2UobXlfZGYkY29uZGl0aW9uLCJcXC5bMC05XSsiLCIiKQpiYXNlIDwtIGdncGxvdChteV9kZixhZXMoY291bnQsIGZpbGw9Y29uZGl0aW9uKSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uY291bnQuLiksYmlucyA9IDUwKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMXAiLCBicmVha3MgPSBOVUxMKQpiYXNlICsgZmFjZXRfd3JhcCh+Z2VuZSkgICsgdGhlbWVfYncoKSArIHhsYWIobGFiZWwgPSAibm9ybWFsaXNlZCBsb2cgY291bnQiKSArIHlsYWIobGFiZWw9ImNlbGwgY291bnQiKQoKCmBgYAoKIyMgdmFyaWF0aW9uIGV4cGxhaW5lZAoKCmBgYHtyfQpyZWFkcyRjb25kaXRpb25fSURfbWFpbiA8LSBzdHJfcmVwbGFjZShteV9yZWFkcyRwb3B1bGF0aW9uLm5hbWUsIiAjWzAtOV0rICIgLCJfIikKcmVhZHMkZ2Vub3R5cGUgPC0gdW5saXN0KHB1cnJyOjptYXAoc3RyX3NwbGl0KHJlYWRzJHBvcHVsYXRpb24ubmFtZSwgIiAiKSwgMSkpCnJlYWRzJHBoZW5vdHlwZSA8LSB1bmxpc3QocHVycnI6Om1hcChzdHJfc3BsaXQocmVhZHMkcG9wdWxhdGlvbi5uYW1lLCAiICIpLCAzKSkKbXlfdmFyczwtZ2V0VmFyaWFuY2VFeHBsYWluZWQocmVhZHMsIGV4cHJzX3ZhbHVlcyA9ICJsb2djb3VudHMiLCB2YXJpYWJsZXMgPSAgYygicG9wdWxhdGlvbi5uYW1lIiwgImNvbmRpdGlvbl9JRF9tYWluIiwiZ2Vub3R5cGUiLCJwaGVub3R5cGUiKSkKcGxvdEV4cGxhbmF0b3J5VmFyaWFibGVzKG15X3ZhcnMpCgpgYGAKCgo=